/**
*		@file Calls.cpp
*		@brief Calls class
*
*		@author Lan Ziquan
*
*		@date 1/25/2012
*/
#include "Calls.h"
vector<ProcSet> Calls::calls_table_;
vector<ProcSet>	Calls::calls_table_t_;
vector<ProcSet>	Calls::calls_adv_table_;
vector<ProcSet>	Calls::calls_adv_table_t_;

ProcSet		Calls::calls_has_p0_;
ProcSet		Calls::calls_has_0p_;
bool		Calls::calls_has_00_;

void Calls::RebuildCalls()
{
	for( int i = 0; i < ProcTable::GetSize(); i++ )
	{
		calls_table_.push_back(ProcTable::GetProcCallees(i+1));
		calls_table_t_.push_back(ProcTable::GetProcCallers(i+1));
	}

	for(int proc_idx_left = 1; proc_idx_left <= ProcTable::GetSize(); proc_idx_left++)
	{

		queue<ProcIdx> q_proc_idx;
		q_proc_idx.push(proc_idx_left);

		ProcSet proc_set_result (calls_table_[proc_idx_left-1].size(), false);
		ProcSet proc_set_partial_result (calls_table_[proc_idx_left-1].size(), false);

		while( !q_proc_idx.empty() )
		{
			ProcIdx temp_idx = q_proc_idx.front();
			q_proc_idx.pop();

			proc_set_partial_result = GetCallsRight(temp_idx);
			proc_set_result = LogicOR<ProcSet>(proc_set_result, proc_set_partial_result);

			for( int i = 0; i < proc_set_partial_result.size(); i++ )
				if( proc_set_partial_result[i] )
					q_proc_idx.push(i+1);
		}

		calls_adv_table_.push_back(proc_set_result);
	}

	calls_adv_table_t_ = calls_adv_table_;

	for(int i = 0; i < ProcTable::GetSize(); i++){
		for(int j = 0; j < ProcTable::GetSize(); j++){
			calls_adv_table_t_[i][j] = calls_adv_table_[j][i];
		}
	}
	calls_has_p0_.resize(ProcTable::GetSize());
	calls_has_0p_.resize(ProcTable::GetSize());
	calls_has_00_ = false;
	return;
}

void Calls::CompleteCalls()
{
	for( int i = 0; i < ProcTable::GetSize(); i++ )
	{
		calls_has_p0_[i] = IsAny<ProcSet>(calls_table_[i]);
		calls_has_0p_[i] = IsAny<ProcSet>(calls_table_t_[i]);
	}
	calls_has_00_ = IsAny<ProcSet>(calls_has_p0_);
	return;
}

ProcSet& Calls::GetCallsRight(ProcIdx proc_idx_left)
{
	return calls_table_[proc_idx_left - 1];
}

ProcSet& Calls::GetCallsLeft(ProcIdx proc_idx_right)
{
	return calls_table_t_[proc_idx_right - 1];
}

ProcSet& Calls::GetCallsAdvRight(ProcIdx proc_idx_left)
{
	return calls_adv_table_[proc_idx_left - 1];
}

ProcSet& Calls::GetCallsAdvLeft(ProcIdx proc_idx_right)
{
	return calls_adv_table_t_[proc_idx_right - 1];
}

bool Calls::IsCalls(ProcIdx proc_idx_left, ProcIdx proc_idx_right)
{
	if( proc_idx_left == 0 )
	{
		if( proc_idx_right == 0 )
			return calls_has_00_;
		else
			return calls_has_0p_[proc_idx_right - 1];
	}
	else
	{
		if( proc_idx_right == 0 )
			return calls_has_p0_[proc_idx_left - 1];
		else
			return calls_table_[proc_idx_left - 1][proc_idx_right - 1];
	}
}

bool Calls::IsCallsAdv(ProcIdx proc_idx_left, ProcIdx proc_idx_right)
{
	if( proc_idx_left == 0 )
	{
		if( proc_idx_right == 0 )
			return calls_has_00_;
		else
			return calls_has_0p_[proc_idx_right - 1];
	}
	else
	{
		if( proc_idx_right == 0 )
			return calls_has_p0_[proc_idx_left - 1];
		else
			return calls_adv_table_[proc_idx_left - 1][proc_idx_right - 1];
	}
}